﻿// <copyright file="AppSharedState.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// </copyright>

namespace Mva.Recognition
{
    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.ApplicationModel.ConversationalAgent;
    using Debug = MvaLib.Diagnostics.Debug;

    /// <summary>
    /// Verifies if background processess and permissions are enabled to manage the application state.
    /// </summary>
    public static class AppSharedState
    {
        private static readonly SemaphoreSlim CachedSessionSemaphore = new SemaphoreSlim(1, 1);
        private static ConversationalAgentSession cachedAgentSession = null;

        /// <summary>
        /// Gets or sets the activation keyword configuration representation for the application.
        /// This is the configuratio that represents the "first stage" keyword spotter that can
        /// launch the application when it's not already running.
        /// </summary>
        //public static ActivationSignalDetectionConfiguration KeywordConfiguration { get; set; }

        ///// <summary>
        ///// Gets or sets a value indicating whether the current active keyword configuration is
        ///// in an application-enabled state.
        ///// </summary>
        //public static bool KeywordEnabledByApp
        //{
        //    get => AppSharedState.KeywordConfiguration?.AvailabilityInfo?.IsEnabled ?? false;
        //    set => AppSharedState.KeywordConfiguration?.SetEnabledAsync(value).AsTask().Wait();
        //}

        /// <summary>
        /// It's not required, but for optimization purposes it's acceptable to cache the ConversationalAgentSession
        /// for the lifetime of the app and use it across background/foreground invocations.
        /// </summary>
        /// <returns>Cached Conversation session state.</returns>
        public static async Task<ConversationalAgentSession> GetSessionAsync()
        {
            Debug.WriteLine("GetSessionAsync start");
            await CachedSessionSemaphore.WaitAsync().ConfigureAwait(false);
            Debug.WriteLine("GetSessionAsync wait end");
            try
            {
                if (cachedAgentSession == null)
                {
                    cachedAgentSession = await Task.Run(async ()=> { return await ConversationalAgentSession.GetCurrentSessionAsync(); }).ConfigureAwait(false);
                    cachedAgentSession.SignalDetected += OnInAppSignalEventDetected;
                    cachedAgentSession.SystemStateChanged += OnSystemStateChanged;
                    if (cachedAgentSession == null)
                    {
                        Debug.WriteLine("Cache agent session failed.");
                    }
                    else
                    {
                        Debug.WriteLine($"Cache agent session ok:{cachedAgentSession.AgentState}");
                    }
                }
                else
                {
                    Debug.WriteLine("cachedAgentSession != null");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Unable to configure a ConversationalAgentSession. Please check your registration with the MVA platform.\r\n{ex.Message}");
            }
            finally
            {
                CachedSessionSemaphore.Release();
            }
            if (cachedAgentSession == null)
            {
                Debug.WriteLine("cachedAgentSession == null");
            }
            else
            {
                Debug.WriteLine($"cachedAgentSession:{cachedAgentSession.AgentState}");
            }
            Debug.WriteLine("GetSessionAsync end");
            return cachedAgentSession;
        }

        public static async Task ResetAgentSessionAsync()
        {
            if(cachedAgentSession != null)
            {
                await cachedAgentSession.RequestAgentStateChangeAsync(ConversationalAgentState.Inactive);
                Debug.WriteLine($"ResetAgentSessionAsync.RequestAgentStateChangeAsync: {cachedAgentSession.AgentState}");
                cachedAgentSession.SignalDetected -= OnInAppSignalEventDetected;
                cachedAgentSession.SystemStateChanged -= OnSystemStateChanged;

                cachedAgentSession = null;
                Debug.WriteLine("ResetAgentSessionAsync end");
            }
        }

        private static void OnSystemStateChanged(ConversationalAgentSession sender, ConversationalAgentSystemStateChangedEventArgs args)
        {
            Debug.WriteLine($"Session, OnSystemStateChanged, type:{args.SystemStateChangeType}");
            if(args.SystemStateChangeType == ConversationalAgentSystemStateChangeType.UserAuthentication)
            {
                UserAuthenticationChanged?.Invoke();
            }
        }
        public static event Action UserAuthenticationChanged;
        private static async void OnInAppSignalEventDetected(ConversationalAgentSession sender, ConversationalAgentSignalDetectedEventArgs args)
        {
            Debug.WriteLine($"\r\n\r\n  '{sender.Signal.SignalName}' signal detected in session event handler");

            // Doing a "heartbeat" ensures we don't get the background event
            var session = await AppSharedState.GetSessionAsync();
            if (session == null)
            {
                Debug.WriteLine("OnInAppSignalEventDetected.RequestAgentStateChangeAsync: session null");
                return;
            }
            await session.RequestAgentStateChangeAsync(session.AgentState);
            Debug.WriteLine($"OnInAppSignalEventDetected.RequestAgentStateChangeAsync: {session.AgentState}");
            //var session = await GetSessionAsync();
            //var dialogManager = await DialogManager.GetInstanceAsync();
            //await dialogManager.ChangeAgentStateAsync(session.AgentState);

            //SignalDetectionHelper.Instance.HandleSignalDetection(DetectionOrigin.FromApplicationObject);

            Recognizer.StartDetection();
        }
    }
}
